var name; //our username 
var connectedUser; //partner username

//connecting to our signaling server
var conn = new WebSocket('wss://www.green-reading.com:9090')

conn.onopen = function () { 
    console.log("Connected to the signaling server"); 
};

//when we got a message from a signaling server 
conn.onmessage = function (msg) { 
    console.log("Got message", msg.data);
    var data = JSON.parse(msg.data); 
    
    switch(data.type) { 
    case "login": 
        handleLogin(data.success); 
        break; 
	//when somebody wants to call us 
    case "offer": 
        handleOffer(data.offer, data.name); 
        break; 
    case "answer": 
        handleAnswer(data.answer); 
        break; 
	//when a remote peer sends an ice candidate to us 
    case "candidate": 
        handleCandidate(data.candidate); 
        break; 
    case "leave": 
        handleLeave(true); 
        break; 
    default: 
        break; 
    }
};

conn.onerror = function (err) { 
    console.log("Got error", err); 
};

//alias for sending JSON encoded messages 
function send(message) { 
    //attach the other peer username to our messages 
    if (connectedUser) { 
	message.name = connectedUser; 
    } 
    conn.send(JSON.stringify(message)); 
};

var loginPage = document.querySelector('#loginPage'); 
var usernameInput = document.querySelector('#usernameInput'); 
var loginBtn = document.querySelector('#loginBtn'); 

var callPage = document.querySelector('#callPage'); 
var callToUsernameInput = document.querySelector('#callToUsernameInput');
var callBtn = document.querySelector('#callBtn'); 
var hangUpBtn = document.querySelector('#hangUpBtn');
callBtn.disabled = true;
hangUpBtn.disabled = true;

var localVideo = document.querySelector('#localVideo'); 
var remoteVideo = document.querySelector('#remoteVideo'); 

var rtc_peer_connection; 
var stream;

callPage.style.display = "none";

// Login when the user clicks the button 
loginBtn.addEventListener("click", function (event) { 
    name = usernameInput.value;
    
    if (name.length > 0) { 
	send({type: "login", name: name}); 
    }
    
});

function generate_random(length){
    var word = "";
    var i;
    for(i = 0; i < length; i++){
	word += (Math.floor(Math.random() * 9) + 1).toString()
    }
    return word;
}

function get_turn_config(){
    TURN_BASE_URL = "https://www.green-reading.com/turn?username="
    turn_username = generate_random(9);
    turn_ceod_key = generate_random(9);
    turn_url = TURN_BASE_URL + turn_username + "&keys=" + turn_ceod_key;
    console.log(turn_url);
    var xmlHttp = new XMLHttpRequest();
    xmlHttp.open( "GET", turn_url, false ); // false for synchronous request
    xmlHttp.send();
    var config = undefined;
    if (xmlHttp.readyState == 4 && xmlHttp.status == 200) {
	var config = JSON.parse(xmlHttp.responseText);
    }
    if(!config){
	//alert("the server is not available now, please retry");
	//window.location.replace(".");
    }

    var iceServer = []
    var i = 0;
    for(i = 0; i < config["uris"].length; i++){
	iceServer.push({
	    "username": config.username,
	    "credential": config.password,
	    "url": config.uris[i]
	})
    };
    var configuration = {"iceServers": iceServer};
    return configuration;
}


function gotStream(stream) {
    //displaying local video stream on the page 
    localVideo.srcObject = stream;
    
    //using Google public stun server 
    var configuration = { 
	"iceServers": [{ "url": "stun:stun2.1.google.com:19302" }]
    };

    var configuration = {"iceServers":
			 [{ "url": "turn:green-reading.com:3478?transport=tcp", "credential":"123456789", "username": "luyao"},
			  { "url": "turn:green-reading.com:3478?transport=udp", "credential":"123456789", "username": "luyao"}]}
    
    configuration = get_turn_config();
    rtc_peer_connection = new RTCPeerConnection(configuration);
    // setup stream listening 
    rtc_peer_connection.addStream(stream); 
    
    //when a remote user adds stream to the peer connection, we display it 
    rtc_peer_connection.onaddstream = function (e) { 
	remoteVideo.srcObject = e.stream; 
    };
    
    // Setup ice handling 
    rtc_peer_connection.onicecandidate = function (event) { 
	if (event.candidate) { 
	    send({type: "candidate", candidate: event.candidate}); 
	} 
    };  
    
}

function handleLogin(success) { 
    if (success === false) { 
	alert("Ooops...try a different username"); 
    } else {
	loginPage.style.display = "none"; 
	callPage.style.display = "block";
	callBtn.disabled = false;
	navigator.mediaDevices.getUserMedia({ video: true, audio: true })
	    .then(gotStream)
	    .catch(
		function (error) {console.log(error);}
	    ); 
    }
};

//initiating a call 
callBtn.addEventListener("click", function () {
    var callToUsername = callToUsernameInput.value;
    
    if (callToUsername.length > 0) {
	callBtn.disabled = true;
	hangUpBtn.disabled = false;
	connectedUser = callToUsername;
	// create an offer 
	rtc_peer_connection.createOffer(
	    function (offer) {
		offer.sdp = preferOpus(offer.sdp);
		send({type: "offer", offer: offer}); 
		rtc_peer_connection.setLocalDescription(offer); 
	    },
	    function (error) { 
		alert("Error when creating an offer"); 
	    });
    }
});

//when somebody sends us an offer 
function handleOffer(offer, name) {
    callBtn.disabled = true;
    hangUpBtn.disabled = false;
    connectedUser = name; 
    rtc_peer_connection.setRemoteDescription(new RTCSessionDescription(offer));
    
    //create an answer to an offer 
    rtc_peer_connection.createAnswer(
	function (answer) {
	    answer.sdp = preferOpus(answer.sdp);
	    rtc_peer_connection.setLocalDescription(answer); 
	    send({type: "answer", answer: answer}); 
	},
	function (error) {alert("Error when creating an answer" + error);}); 
};

//when we got an answer from a remote user
function handleAnswer(answer) { 
    rtc_peer_connection.setRemoteDescription(new RTCSessionDescription(answer)); 
};

//when we got an ice candidate from a remote user 
function handleCandidate(candidate) { 
    rtc_peer_connection.addIceCandidate(new RTCIceCandidate(candidate)); 
};

//hang up 
hangUpBtn.addEventListener("click", function () {
    send({type: "leave"});
    handleLeave(false); 
});

function handleLeave(peer_exited) {
    callBtn.disabled = false;
    hangUpBtn.disabled = true;
    connectedUser = null; 
    remoteVideo.src = null; 
    
    rtc_peer_connection.close(); 
    rtc_peer_connection.onicecandidate = null; 
    rtc_peer_connection.onaddstream = null;
    if(peer_exited) {
	alert("peer has exited")
    }
    else {
	alert("close the connection")
    }
    window.location.replace(".")
};

// Set Opus as the default audio codec if it's present.
function preferOpus(sdp) {
  var sdpLines = sdp.split('\r\n');
  var mLineIndex;
  // Search for m line.
  for (var i = 0; i < sdpLines.length; i++) {
    if (sdpLines[i].search('m=audio') !== -1) {
      mLineIndex = i;
      break;
    }
  }
  if (mLineIndex === null) {
    return sdp;
  }

  // If Opus is available, set it as the default in m line.
  for (i = 0; i < sdpLines.length; i++) {
    if (sdpLines[i].search('opus/48000') !== -1) {
      var opusPayload = extractSdp(sdpLines[i], /:(\d+) opus\/48000/i);
      if (opusPayload) {
        sdpLines[mLineIndex] = setDefaultCodec(sdpLines[mLineIndex],
          opusPayload);
      }
      break;
    }
  }

  // Remove CN in m line and sdp.
  sdpLines = removeCN(sdpLines, mLineIndex);

  sdp = sdpLines.join('\r\n');
  return sdp;
}

function extractSdp(sdpLine, pattern) {
  var result = sdpLine.match(pattern);
  return result && result.length === 2 ? result[1] : null;
}

// Set the selected codec to the first in m line.
function setDefaultCodec(mLine, payload) {
  var elements = mLine.split(' ');
  var newLine = [];
  var index = 0;
  for (var i = 0; i < elements.length; i++) {
    if (index === 3) { // Format of media starts from the fourth.
      newLine[index++] = payload; // Put target payload to the first.
    }
    if (elements[i] !== payload) {
      newLine[index++] = elements[i];
    }
  }
  return newLine.join(' ');
}

// Strip CN from sdp before CN constraints is ready.
function removeCN(sdpLines, mLineIndex) {
  var mLineElements = sdpLines[mLineIndex].split(' ');
  // Scan from end for the convenience of removing an item.
  for (var i = sdpLines.length - 1; i >= 0; i--) {
    var payload = extractSdp(sdpLines[i], /a=rtpmap:(\d+) CN\/\d+/i);
    if (payload) {
      var cnPos = mLineElements.indexOf(payload);
      if (cnPos !== -1) {
        // Remove CN payload from m line.
        mLineElements.splice(cnPos, 1);
      }
      // Remove CN line in sdp
      sdpLines.splice(i, 1);
    }
  }

  sdpLines[mLineIndex] = mLineElements.join(' ');
  return sdpLines;
}
